package com.lagou.edu.factory;

import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Service;
import com.lagou.edu.annotation.Transactional;
import com.lagou.edu.pojo.BeanDefinition;
import com.lagou.edu.utils.ClassUtil;
import com.lagou.edu.utils.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 应癫
 *
 * 工厂类，生产对象（使用反射技术）
 */
public class BeanFactory {


    /**
     * 任务一：读取解析xml，通过反射技术实例化对象并且存储待用（map集合）
     * 任务二：对外提供获取实例对象的接口（根据id获取）
     */

    public static Map<String,Object> map = new HashMap<>();  // 存储对象

    public static Map<String,Object> mapProxy = new HashMap<>();  // 存储对象

    public static List<BeanDefinition> list = new ArrayList<>();


    static {
        // 任务一：读取解析xml，通过反射技术实例化对象并且存储待用（map集合）
        // 加载xml
        InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
        // 解析xml
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();

            //实例化bean（先解析xml配置bean信息，再解析注解实例化bean）
            List<Element> beanList = rootElement.selectNodes("//bean");
            for (int i = 0; i < beanList.size(); i++) {
                Element element = beanList.get(i);
                BeanDefinition beanDefinition = BeanDefinition.class.newInstance();
                String id = element.attributeValue("id");        // accountDao
                String clazz = element.attributeValue("class");
                beanDefinition.setId(id);
                beanDefinition.setBeanClass(clazz);
                List<Element> propertyList = element.elements();
                for (int j = 0; j < propertyList.size(); j++) {
                    Element elementProperty = propertyList.get(j);   //<property name="AccountDao" ref="accountDao"></property>
                    String name = elementProperty.attributeValue("name");
                    String ref = elementProperty.attributeValue("ref");
                    Map<String, String> propertyMap = new HashMap<>();
                    propertyMap.put(name, ref);
                    beanDefinition.setPropertys(propertyMap);
                }
                list.add(beanDefinition);
            }
            //获取扫描包路径,解析路径下的注解，实例化bean注册进容器
            List<Element> scanList = rootElement.selectNodes("//scan");
            for (Element element : scanList) {
                // 处理每个bean元素，获取到该元素的id 和 class 属性
                String packgeName = element.attributeValue("packege");
                List<Class<?>> classes = ClassUtil.getClasses(packgeName);
                for (Class<?> aClass : classes) {
                    //解析Service 注解 封装BeanDefinition
                    if(aClass.isAnnotationPresent(Service.class)){
                        BeanDefinition beanDefinition = BeanDefinition.class.newInstance();
                        beanDefinition.setId(StringUtils.toLowerCaseFirstOne(aClass.getSimpleName()));
                        beanDefinition.setBeanClass(aClass.getName());
                        beanDefinition.setPackageName(packgeName);

                        //解析Autowired注解
                        Field[] declaredFields = aClass.getDeclaredFields();
                        Map<String, String> propertyMap = new HashMap<>();
                        for (Field declaredField : declaredFields) {
                            if( declaredField.isAnnotationPresent(Autowired.class)){
                                String name = declaredField.getName();
                                // key:bean类型-->AccountDao  value:bean 名称-->accountDao
                                propertyMap.put(declaredField.getType().getSimpleName(), name);
                            }
                        }
                        beanDefinition.setPropertys(propertyMap);
                        list.add(beanDefinition);
                    }

                }
            }
            //真正开始是实例化bean
            AbstractBeanFactory.doCreateBean();

            } catch (Exception e) {
            e.printStackTrace();
        }

    }



    // 任务二：对外提供获取实例对象的接口（根据id获取）
    public static  Object getBean(String id) {
        if(null != mapProxy.get(id)){
            return mapProxy.get(id);
        }
        return map.get(id);
    }

}
